﻿using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Web.Http;
using Tyche.Common.ProxyBuilder;
using Tyche.Common.Resource;
using Tyche.WebApiClient.Http;

namespace Tyche.WebApiClient
{
    public class TycheWebApiClientBuilder : ITycheProxyBuilder
    {
        /// <summary>
        /// host
        /// </summary>
        private string host;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="host"></param>
        public TycheWebApiClientBuilder(string host)
        {
            this.host = host;
        }

        /// <summary>
        /// 构建代理
        /// </summary>
        /// <param name="moduleBuilder"></param>
        /// <param name="type"></param>
        public void Build(ModuleBuilder moduleBuilder, Type type)
        {
            var resource = TycheResourceManager.GetResource(type);

            if (resource.Proxy != null)
            {
                return;
            }

            var typeBuilder = moduleBuilder.DefineType(resource.Interface.Name
                , TypeAttributes.Class | TypeAttributes.Public
                , null
                , new Type[] { resource.Interface });

            foreach (var method in resource.Interface.GetMethods().Where(m => m.ReturnType != typeof(void)))
            {
                // 参数类型
                var parameterTypes = method.GetParameters().Select(p => { return p.ParameterType; }).ToArray();

                var methodBuilder = typeBuilder.DefineMethod(method.Name
                    , MethodAttributes.Public
                    | MethodAttributes.HideBySig
                    | MethodAttributes.NewSlot
                    | MethodAttributes.Virtual
                    | MethodAttributes.Final
                    , method.ReturnType
                    , parameterTypes);

                var isHttpMethodGet = method.GetCustomAttributes(typeof(HttpGetAttribute)).Any();

                var generator = methodBuilder.GetILGenerator();

                generator.Emit(OpCodes.Ldstr, host);
                generator.Emit(OpCodes.Ldstr, type.Name.TrimStart('I'));
                generator.Emit(OpCodes.Ldstr, method.Name);

                if (parameterTypes.Length > 0)
                {
                    generator.Emit(OpCodes.Ldarg, 1);
                }
                else
                {
                    generator.Emit(OpCodes.Ldnull);
                }

                if (isHttpMethodGet)
                {
                    generator.Emit(OpCodes.Call
                        , typeof(TycheHttpUtil).GetMethod("Get", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(method.ReturnType));
                }
                else
                {
                    generator.Emit(OpCodes.Call
                        , typeof(TycheHttpUtil).GetMethod("Post", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(method.ReturnType));
                }

                generator.Emit(OpCodes.Ret);
            }

            resource.Proxy = typeBuilder.CreateType();
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void Register<T>()
        {
            TycheResourceManager.SetResource(null, typeof(T), null, null, this);
        }
    }
}
